<?php

class Mvc {
	private $controllers = array();			// Collection of controller files
	private $models = array();				// Collection of model files
	
	/**
	 * Construct of MVC
	 */
	public function __construct() {
		$this->check_mvc_dirs();
	}	
	
	/**
	 * This method provides the MVC-model stucture,
	 * Is checks for the right implementation to.
	 * @param object $dp Dispatcher Reference.
	 * @access public
	 */
	public function open_mvc_page($dp) {

		if($dp->classname == '') $dp->setClassname(INDEXFILE_KEYWORD);
		if(!$this->controllers[$dp->classname]) throw new Exception('Controller "'.$dp->classname.'" not found. Please ensure the file "'.$dp->classname.'.controller.php" exists in de "app/controllers/" directory.', 404);
		if(!$this->models[$dp->classname]) throw new Exception('Model "'.$dp->classname.'" not found. Please ensure the file "'.$dp->classname.'.model.php" exists in de "app/models/" directory.', 404);
		
		if(file_exists($this->controllers[$dp->classname]) && file_exists($this->models[$dp->classname])){
			include($this->controllers[$dp->classname]);
			include($this->models[$dp->classname]);
		} else {
			throw new Exception('Can not find controller and model for "'.$dp->classname.'".', 404);
		}
		
		if(class_exists($dp->classname)) {
			if(method_exists($dp->classname, $dp->functionname) || $dp->functionname == '') {
				
				if($dp->functionname == '') $dp->setFunctionname('Main');
				
				$eval_model_name = $dp->classname . 'model';
				if(!class_exists($eval_model_name)) throw new Exception('Classname of the model in file "'.$dp->classname.'.model.php" must be named to "'. $dp->classname . 'Model". The classname is case insensitive.', 501);
				
				eval("\$mvccontroller = new \$dp->classname();");
				eval("\$mvcmodel = new \$eval_model_name();"); 
				
				if($mvcmodel instanceof Model == false) throw new Exception('Class "' . $eval_model_name . '" in file "'.$dp->classname.'.model.php" must extend Model.', 501 );
				if($mvccontroller instanceof Controller == false) throw new Exception('Class "' . $dp->classname . '" in file "'.$dp->classname.'.controller.php" must extend Controller.', 501 );
				if($mvccontroller instanceof IController == false) throw new Exception('Class "' . $dp->classname . '" in file "'.$dp->classname.'.controller.php" must implement IController.', 501 );

				$mvccontroller->model = $mvcmodel;
				@call_user_func_array(array($mvccontroller, $dp->functionname), $dp->functionparams);
				
			} else {
				throw new Exception('Function "'.$dp->functionname.'()" of class "' . $dp->classname . '" does not exists in the file "'.$dp->classname .'.controller.php".', 404 );				
			}
			
		} else {
			throw new Exception('Class "' . $dp->classname . '" not found in file "' . $dp->classname . '.controller.php".', 501 );
		}
	}
	
	/**
	 * Checks the folders for the controllers, models and views and
	 * collect the files.
	 * @access private
	 */
	private function check_mvc_dirs() {
		$this->controllers = $this->search_files($this->check_create_dir('controllers'), 'controller');
		$this->models = $this->search_files($this->check_create_dir('models'), 'model');
		$this->check_create_dir('views');
	}
	
	/**
	 * Checks if the folder exists, if not, try to create it.
	 * @access private
	 * @return The created directorypath
	 */
	private function check_create_dir($dirname) {
		if(!is_dir(CONFIG_APP.$dirname)) {
			if(!is_writable(CONFIG_APP) || !mkdir(CONFIG_APP.$dirname)) {
				throw new Exception('Error: Folder "'.$dirname.'" can not be found in '.CONFIG_APP.' folder.');
			}
		}
		return CONFIG_APP.$dirname;
	}
	
	/**
	 * Recursively search for the files.
	 * @param string $searchdir The directory we need to start the search in
	 * @param string $class_keyword The class keyword.
	 * @access private
	 * @return array of files
	 */
	private function search_files($searchdir, $class_keyword = '') {
		$files = array();
		if(is_dir($searchdir)) {
			if($h = opendir($searchdir)) {
				while(false !== ($file = readdir($h))){
					if ($file != "." && $file != "..") {
						if(is_dir($searchdir.'/'.$file)) {
							$files_from_dir = $this->search_files($searchdir.'/'.$file, $class_keyword);
							if(is_array($files_from_dir )) $files = array_merge($files, $files_from_dir );
						}
						if(is_file($searchdir.'/'.$file)) {
							$keywordmatch= preg_match('/(.*)\.'.$class_keyword.'\.php$/',$file,$matches);
							
							if($keywordmatch > 0) {
								$key = $matches[1];
								if(array_key_exists($key, $files)) throw new Exception('Error: Duplicated ' . $class_keyword . ' "'.$key.'" in "' . $searchdir . '" directory found.', 501);
								$files[$key] = strtolower($searchdir.'/'.$file);
							}
						}
					}
				}
				closedir($h); 
			}
		}
		return $files;	
	}
}
?>